/*数据管理模块---用户信息表*/
#ifndef __M_DB_H__
#define __M_DB_H__
#include "util.hpp"

#include "logger.hpp"
#include <mutex>
#include <assert.h>
class user_table
{
private:
    MYSQL *mysql_;
    std::mutex mutex_;

public:
    user_table(
        const std::string &host,
        const std::string &username,
        const std::string &password,
        const std::string &dbname,
        uint16_t port = 3306)
    {
        mysql_ = mysql_util::mysql_create(host,username,password,dbname,port);
        assert(mysql_!=NULL);
    }
    ~user_table() {
        mysql_util::mysql_destroy(mysql_);
        mysql_=nullptr;
    }


    bool insert(Json::Value& user) {
#define INSERT_USER "insert  user values(null,'%s',password('%s'),1000,0,0);"
        // //判断用户是否已存在
        // Json::Value val;
        // bool sel=select_by_name(user["username"].asCString(),val);
        // if(sel==true){
        //     DLOG("user:%s is Already exists",user["username"].asCString());
        //     return false;
        // }
        
        //校验
        if(user["username"].isNull()||user["password"].isNull())
        {
            DLOG("INPUT PASSWORD or USERNAME");
            return false;
        }
        
        char sql[4096]={0};
        //格式化写入
        sprintf(sql,INSERT_USER,user["username"].asCString(),user["password"].asCString());
        bool ret=mysql_util::mysql_exec(mysql_,sql);//执行sql
        if(ret==false){
            ELOG("insert user info failed!\n");
            return false;
        }
        return true;
    }

    bool login(Json::Value&user)
    {
        //以用户名和密码共同作为查询过滤条件并返回所有信息
#define LOGIN_USER "select id,score,total_count,win_count from user where username='%s' and password=password('%s');"
        char sql[4096]={0};
        //格式化写入
        sprintf(sql,LOGIN_USER,user["username"].asCString(),user["password"].asCString());
        MYSQL_RES* res=nullptr;
        {
            //加锁保护
            std::unique_lock<std::mutex> lock(mutex_);
            bool ret=mysql_util::mysql_exec(mysql_,sql);//执行sql
            if(ret==false){
                DLOG("user login  failed!\n");
                return false;
            }
            
            res=mysql_store_result(mysql_);//保存查询结果到本地
            if(res==nullptr){
                DLOG("have no login user info!!");
                return false;
            }
        }
        

        //检查是否唯一
        int row_num=mysql_num_rows(res);
        if(row_num!=1){
            DLOG("The information queried is not unique or zero");
            return false;
        }
        //遍历结果集
        MYSQL_ROW row=mysql_fetch_row(res);
        user["id"] = (Json::UInt64)std::stol(row[0]);
        user["score"] = (Json::UInt64)std::stol(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);//释放结果集
        return true;
    
    }


    bool select_by_name(const std::string&name,Json::Value& user)
    {
#define SELECT_BY_NAME "select id,score,total_count,win_count from user where username='%s';"
        char sql[4096]={0};
        //格式化写入
        sprintf(sql,SELECT_BY_NAME,name.c_str());

        MYSQL_RES* res=nullptr;

        {
            //加锁保护
            std::unique_lock<std::mutex> lock(mutex_);
            bool ret=mysql_util::mysql_exec(mysql_,sql);//执行sql
            if(ret==false){
                DLOG("GET user by name  failed!\n");
                return false;
            }
            //检查结果是否只有一条数据
            res=mysql_store_result(mysql_);//保存结果到本地
            if(res==nullptr){
                DLOG("have no  user info!!");
                return false;
            }
        }
        //检查是否唯一
        int row_num=mysql_num_rows(res);
        if(row_num!=1){
            DLOG("The information queried is not unique");
            return false;
        }
        //遍历结果集
        MYSQL_ROW row=mysql_fetch_row(res);
        user["id"] = std::stoi(row[0]);
        user["username"]=name;
        user["score"] = (Json::UInt64)std::stol(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);
        return true;
    }

    bool select_by_id(uint64_t id,Json::Value& user){
#define SELECT_BY_ID "select username,score,total_count,win_count from user where id='%d';"
        char sql[4096]={0};
        //格式化写入
        sprintf(sql,SELECT_BY_ID,id);
        MYSQL_RES* res=nullptr;

        {
            //加锁保护
            std::unique_lock<std::mutex> lock(mutex_);
            bool ret=mysql_util::mysql_exec(mysql_,sql);//执行sql
            if(ret==false){
                DLOG("GET user by id  failed!\n");
                return false;
            }
            
            res=mysql_store_result(mysql_);//保存结果到本地
            if(res==nullptr){
                DLOG("have no  user info!!");
                return false;
            }
        }
        //检查是否唯一
        int row_num=mysql_num_rows(res);
        if(row_num != 1){
            DLOG("The information queried is not unique");
            return false;
        }
        //遍历结果集
        MYSQL_ROW row=mysql_fetch_row(res);
        user["id"] = (Json::UInt64)id;
        user["username"]=row[0]; 
        user["score"] = (Json::UInt64)std::stol(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);
        return true;
    }

    //胜利时分数增加
    bool win(uint64_t id){
        //胜利一场每次加30分，战斗场次+1，胜利+1
#define USER_WIN "update user set score=score+30,total_count=total_count+1,win_count=win_count+1 where id=%d;"        
        char sql[4096]={0};
        sprintf(sql,USER_WIN,id);
        bool ret=mysql_util::mysql_exec(mysql_,sql);//执行sql
        if(ret==false){
            DLOG("win update  failed!\n");
            return false;
        }
        return true;
    }
    //失败扣分
    bool lose(uint64_t id){
#define USER_LOSE "update user set score=score-30,total_count=total_count+1 where id=%d;"        
        char sql[4096]={0};
        sprintf(sql,USER_LOSE,id);
        bool ret=mysql_util::mysql_exec(mysql_,sql);//执行sql
        if(ret==false){
            DLOG("lose update  failed!\n");
            return false;
        }
        return true;
    }

};

#endif